package cc.owoo.godpen.analysis.css;

import cc.owoo.godpen.analysis.StringAnalysis;

/**
 * 选择器解析
 * Created by nimensei
 * 2022-06-01 上午 01:20
 */
class SelectorAnalysis {
    private enum Type {
        TAG,// 标签选择器
        ID,// id选择器
        CLASS// class选择器
    }

    private final StringAnalysis analysis;// 字符串解析对象
    private final SelectorGroup selectorGroup = new SelectorGroup();// 解析结果
    private SelectorSingle selectorSingle;// 当前解析结果
    private Type type = Type.TAG; // 当前选择器节点类型
    private boolean isChild;// 是否需要添加子元素选择器
    private boolean isNext;// 是否不切换至子元素选择器
    private int before = -1;// 当前选择器节点开始位置

    public SelectorAnalysis(StringAnalysis analysis) {
        this.analysis = analysis;
    }

    /**
     * 开始解析
     *
     * @param end 结束符
     * @return 解析结果
     */
    public SelectorGroup analysis(char end) {
        while (analysis.hashNext()) {
            char c = analysis.next();
            if (c == end)
                break;
            switch (c) {
                case ',':
                    appendSelectorNode();
                    break;
                case '#':
                    setType(Type.ID);
                    break;
                case '.':
                    setType(Type.CLASS);
                    break;
                case '*':
                    System.out.println(isChild);
                    break;
                case '>':
                    appendSymbolSelector(new ChildrenSelector());
                    break;
                case '+':
                    appendSymbolSelector(new BrotherSelector());
                    break;
                case '~':
                    appendSymbolSelector(new BrothersSelector());
                    break;
                case '[':
                    appendSelectorNode();
                    analysisAttributeSelector(end);
                    break;
                case ':':
                    appendSelectorNode();
                    analysisClassSelector(end);
                    break;
                default:
                    if (c <= 32) {
                        if (selectorSingle == null)
                            break;
                        appendSelectorNode();
                        isChild = true;
                    } else if (before == -1)
                        before = analysis.getIndex();
                    break;
            }
        }
        appendSelector();
        if (selectorGroup.size() == 0)
            return null;
        return selectorGroup;
    }

    /**
     * 设置当前类型
     *
     * @param type 类型
     */
    private void setType(Type type) {
        appendSelectorNode();
        this.type = type;
    }

    /**
     * 添加符号类选择器节点
     *
     * @param node 选择器节点
     */
    private void appendSymbolSelector(SelectorNode node) {
        appendSelectorNode();
        appendSelectorNode(node);
        isNext = true;
        type = Type.TAG;
    }

    /**
     * 解析属性选择器
     *
     * @param end 结束符号
     */
    private void analysisAttributeSelector(char end) {
        int before = analysis.getNextIndex();
        String name = null;
        Examine examine = null;
        while (analysis.hashNext()) {
            char c = analysis.next();
            if (c == end || c == ']')
                break;
            if (c == '=' && name == null) {
                if (analysis.getIndex() <= before) {
                    name = "";
                    before = analysis.getIndex();
                    continue;
                }
                examine = Examine.createExamine(analysis.charAt(analysis.getIndex() - 1));
                name = analysis.substring(before, analysis.getIndex() - (examine == null ? 0 : 1));
                if (examine == null)
                    examine = Examine.EQUALS;
                before = analysis.getIndex();
            }
        }
        String condition;
        if (analysis.getIndex() > before) {
            condition = analysis.substring(before);
            if (name == null) {
                name = condition;
                condition = null;
            }
        } else
            condition = null;
        appendSelectorNode(new AttributeSelector(name, condition, examine));
    }

    /**
     * 解析伪类选择器、伪元素
     *
     * @param end 结束符
     */
    private void analysisClassSelector(char end) {
        int before = analysis.getNextIndex();
        String params = null;
        char c = ' ';
        while (analysis.hashNext()) {
            c = analysis.next();
            if (c == end || c == '(' || c <= 32)
                break;
        }
        String name = analysis.substring(before);
        if (c == '(') {
            before = analysis.getNextIndex();
            analysis.nextIndexOf(')');
            params = analysis.substring(before);
        }
        System.out.println(name + ", " + params);
    }

    /**
     * 将当前选择器添加到结果列表
     */
    private void appendSelector() {
        appendSelectorNode();
        if (selectorSingle == null)
            return;
        selectorGroup.add(selectorSingle);
        selectorSingle = null;
    }

    /**
     * 将当前选择器节点添加到选择器中
     */
    private void appendSelectorNode() {
        if (before == -1)
            return;
        if (before >= analysis.getIndex()) {
            before = -1;
            return;
        }
        String name = analysis.substring(before).trim();
        if (name.length() == 0) {
            before = -1;
            return;
        }
        SelectorNode node = switch (type) {
            case ID -> new IdSelector(name);
            case CLASS -> new ClassSelector(name);
            default -> new TagSelector(name);
        };
        appendSelectorNode(node);
        before = -1;
        type = Type.TAG;
    }

    /**
     * 添加选择器节点
     *
     * @param node 选择器节点
     */
    private void appendSelectorNode(SelectorNode node) {
        if (selectorSingle == null)
            selectorSingle = new SelectorSingle();
        if (isChild) {
            if (!isNext)
                selectorSingle.append(SelectorSingle.CHILD_SELECTOR);
            isChild = isNext = false;
        }
        selectorSingle.append(node);
    }
}
